package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zzyl.config.JsapiPayParam;
import com.zzyl.constant.SuperConstant;
import com.zzyl.constant.TradingConstant;
import com.zzyl.entity.RefundRecord;
import com.zzyl.entity.Trading;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.TradingStateEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.TradingMapper;
import com.zzyl.properties.WeChatProperties;
import com.zzyl.service.RefundRecordService;
import com.zzyl.service.TradingService;
import com.zzyl.utils.WeChatPayUtil;
import com.zzyl.vo.TradingVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 交易订单表 服务实现类
 */
@Slf4j
@Service
public class TradingServiceImpl implements TradingService {
	
	@Autowired
	private TradingMapper tradingMapper;
	@Autowired
	private WeChatPayUtil weChatPayUtil;
	
	@Autowired
	private WeChatProperties weChatProperties;
	@Autowired
	private RefundRecordService refundRecordService;
	
	/**
	 * 根据交易订单号查询交易信息
	 */
	@Override
	public Trading findTradByTradingOrderNo(Long tradingOrderNo) {
		return tradingMapper.selectByTradingOrderNo(tradingOrderNo);
	}
	
	/**
	 * 根据商品订单号查询交易信息
	 */
	@Override
	public Trading findTradByProductOrderNo(Long productOrderNo, String tradingType) {
		return tradingMapper.selectByProductOrderNo(productOrderNo, tradingType);
	}
	
	/**
	 * 根据交易状态查询交易列表
	 */
	@Override
	public List<Trading> findListByTradingState(TradingStateEnum tradingState, Integer count) {
		count = NumberUtil.max(count, 10);
		return tradingMapper.selectListByTradingState(tradingState.getCode(), count);
	}
	
	/**
	 * 新增或修改交易信息
	 */
	@Override
	public Boolean saveOrUpdate(Trading trading) {
		if (trading.getId() == null) {
			return tradingMapper.insert(trading) > 0;
		} else {
			return tradingMapper.updateByPrimaryKey(trading) > 0;
		}
	}
	
	/**
	 * 创建交易单
	 * @param trading 交易单信息
	 * @return 交易单
	 */
	@Override
	public TradingVo createTrading(Trading trading) {
		String jsonStr = weChatPayUtil.jsapi(trading.getTradingOrderNo().toString(), trading.getTradingAmount(), trading.getMemo(), trading.getOpenId());
		JSONObject payJsonObject = JSON.parseObject(jsonStr);
		String prepayId = payJsonObject.getString("prepay_id");
		if (ObjectUtil.isEmpty(payJsonObject) || ObjectUtil.isEmpty(prepayId)) {
			throw new BaseException(BasicEnum.APPLY_TRADE_FAIL);
		}
		
		//封装JSAPI调起支付的参数（给前端使用）
		Long timeStamp = System.currentTimeMillis() / 1000;
		String nonceStr = IdUtil.simpleUUID();
		String packages = "prepay_id=" + prepayId;
		
		String paySign = null;
		try {
			paySign = weChatPayUtil.createPaySign(timeStamp, nonceStr, packages);
		} catch (Exception e) {
			throw new BaseException(BasicEnum.GET_PAYMENT_SIGNATURE_FAIL);
		}
		
		JsapiPayParam jsapiPayParam = JsapiPayParam.builder()
				.timeStamp(timeStamp)
				.appId(weChatProperties.getAppId())
				.nonceStr(nonceStr)
				.packages(packages)
				.paySign(paySign)
				.build();
		
		//封装交易单各项参数
		trading.setIsRefund(SuperConstant.NO);
		trading.setEnterpriseId(Long.valueOf(weChatProperties.getMchId()));
		trading.setPlaceOrderCode(String.valueOf(BasicEnum.SUCCEED.getCode()));
		//设置jsapi调起支付的参数
		trading.setPlaceOrderJson(JSONUtil.toJsonStr(jsapiPayParam));
		trading.setTradingState(TradingConstant.TRADE_WAIT_BUYER_PAY_1);
		trading.setTradingChannel("小程序支付");
		this.saveOrUpdate(trading);
		
		return BeanUtil.toBean(trading, TradingVo.class);
	}
	
	/**
	 * 关闭交易单
	 * @param tradingVo 交易单
	 * @return 已关闭的交易单
	 */
	@Override
	public TradingVo closeTrading(TradingVo tradingVo) {
		try {
			weChatPayUtil.closeTrading(tradingVo.getTradingOrderNo().toString());
		} catch (Exception e) {
			throw new BaseException(BasicEnum.CLOSE_TRADING_FAIL);
		}
		
		Trading trading = findTradByTradingOrderNo(tradingVo.getTradingOrderNo());
		trading.setTradingState(TradingConstant.TRADE_CLOSED_5);
		saveOrUpdate(trading);
		return BeanUtil.toBean(trading, TradingVo.class);
	}
	
	/**
	 * 交易单退款
	 * @param tradingVo 交易单
	 * @return 已退款交易单
	 */
	@Override
	public TradingVo refundTrading(TradingVo tradingVo) {
		//1、生成退款请求编号
		tradingVo.setOutRequestNo(IdUtil.getSnowflakeNextId());
		Trading tradingHandler = findTradByTradingOrderNo(tradingVo.getTradingOrderNo());
		tradingVo.setTradingAmount(tradingHandler.getTradingAmount());
		tradingVo.setRefund(tradingHandler.getRefund());
		tradingVo.setOperTionRefund(tradingHandler.getTradingAmount());
		
		//调用微信退款
		String refundResult = weChatPayUtil.refund(
				tradingVo.getTradingOrderNo().toString(),
				tradingVo.getOutRequestNo().toString(),
				tradingVo.getOperTionRefund(),
				tradingVo.getTradingAmount());
		JSONObject refundJsonObject = JSON.parseObject(refundResult);
		
		//保存退款单信息
		RefundRecord refundRecord = RefundRecord.builder()
				.enterpriseId(tradingHandler.getEnterpriseId())
				.refundNo(tradingVo.getOutRequestNo())
				.refundAmount(tradingVo.getOperTionRefund())
				.productOrderNo(tradingHandler.getProductOrderNo())
				.tradingChannel(tradingHandler.getTradingChannel())
				.tradingOrderNo(tradingHandler.getTradingOrderNo())
				.memo(tradingVo.getTradingChannel())
				.build();
		refundRecord.setCreateTime(LocalDateTime.now());
		refundRecord.setRemark(tradingVo.getTradingChannel());
		refundRecord.setCreateType(tradingVo.getCreateType());
		switch (refundJsonObject.getString("status")) {
			//退款状态：0-未知错误 1-退款中，2-成功, 3-失败
			case TradingConstant.WECHAT_REFUND_SUCCESS:
				refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_SENDING_1);
				break;
			case TradingConstant.WECHAT_REFUND_CLOSED:
				refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_CLOSED_3);
				break;
			case TradingConstant.WECHAT_REFUND_PROCESSING:
				refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_SENDING_1);
				break;
			default:
				refundRecord.setRefundStatus(TradingConstant.REFUND_STATUS_FAIL_0);
				break;
		}
		refundRecordService.saveOrUpdate(refundRecord);
		
		return BeanUtil.toBean(tradingHandler, TradingVo.class);
	}
	
	/***
	 *  统一收单线下交易查询
	 * 该接口提供所有支付订单的查询，商户可以通过该接口主动查询订单状态，完成下一步的业务逻辑。
	 * @param tradingVo 交易单
	 * @return 交易单
	 */
	@Override
	public TradingVo queryTrading(TradingVo tradingVo) {
		Trading tradingHandler = findTradByTradingOrderNo(tradingVo.getTradingOrderNo());
		String tradingJsonStr = weChatPayUtil.queryTrading(String.valueOf(tradingVo.getTradingOrderNo()));
		JSONObject tradingJsonObject = JSON.parseObject(tradingJsonStr);
		
		
		//交易单状态【1-待付款,2-付款中,3-付款失败,4-已结算,5-取消订单】
		switch (tradingJsonObject.getString("trade_state")) {
			case TradingConstant.WECHAT_TRADE_CLOSED:
				tradingHandler.setTradingState(TradingConstant.TRADE_CLOSED_5);
				break;
			case TradingConstant.WECHAT_TRADE_REVOKED:
				tradingHandler.setTradingState(TradingConstant.TRADE_CLOSED_5);
				break;
			case TradingConstant.WECHAT_TRADE_SUCCESS:
				tradingHandler.setTradingState(TradingConstant.TRADE_SUCCESS_4);
				break;
			case TradingConstant.WECHAT_TRADE_REFUND:
				tradingHandler.setTradingState(TradingConstant.TRADE_SUCCESS_4);
				break;
			default:
				log.error("查询交易单获得未知状态" + tradingJsonObject.getString("trade_state"));
				throw new BaseException(BasicEnum.UNKNOWN_TRADING_STATUS);
		}
		
		//修改交易单状态
		tradingHandler.setResultCode(tradingJsonObject.getString("trade_state"));
		tradingHandler.setResultJson(tradingJsonStr);
		saveOrUpdate(tradingHandler);
		return tradingVo;
	}
}


